#include <stm32l4xx.h>

#include <linux/sched.h>
#include <linux/clockchips.h>
#include <linux/jiffies.h>

static inline void systick_disable(void)
{
    SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
}

static int stm32_clock_event_set_state(struct clock_event_device *ce, int state)
{
    systick_disable();

    return 0;
}

static int stm32_clock_event_set_next_event(struct clock_event_device *clkevt, 
                                            unsigned long evt)
{
    SysTick->LOAD = evt;
    SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;

    return 0;
}

static struct clock_event_ops _ops = {
    .set_state = stm32_clock_event_set_state,
    .set_next_event = stm32_clock_event_set_next_event,
};

static struct clock_event_device _clock_event = {
    .ops = &_ops,
    .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
};

void __hal_SysTick_Handler(void)
{
    if (clockevent_state_oneshot(&_clock_event))
    {
        systick_disable();
    }

    clockevents_handle(&_clock_event);
}

void timer_probe(void)
{
    struct clock_event_device *ce = &_clock_event;

    clockevents_config_and_register(ce, SystemCoreClock, 100, 16000000);

    HAL_SYSTICK_Config(SystemCoreClock / CONFIG_HZ);

    NVIC_SetPriority(SysTick_IRQn, 0xFF);
}
